/**************************************************************
*   This software is confidential and contains code, algorithms 
* and know-how proprietary to Saber Interactive.
*
* Copyright (c), Saber Interactive, Inc. 2001-2011
***************************************************************
*
* DS_COMM.H
*
* Common DS functionality
***************************************************************/

#ifndef _DS_COMM_H_
#define _DS_COMM_H_

#pragma once

//#include <ap\ap_comm.h>
//#include <ap\ap_dlstat.h>

#define _AP_PC

//
// Compare functor
//
class dsCMP {
public:
   template <class A, class B> int  cmp      (const A &a, const B &b) const { return (a < b) ? -1 : ((b < a) ? 1 : 0); }
};

template <class T>
class dsCMP_INV {
public:
   dsCMP_INV(const T & cmp_) : cmp_(cmp_) {}
   template <class A, class B> int cmp       (const A & a, const B & b) const { return cmp_.cmp(b, a); }
private:
   const T & cmp_;
};

class dsCMP_EQ {
public:
   template <class A, class B> int  cmp      (const A &a, const B &b) const { return (a == b) ? 0 : 1; }
};

#define dsDECL_CMP(TYPE, KEY, NAME)                                                       \
struct CMP {                                                                              \
   int cmp(const TYPE &a, const TYPE &b) const { return ds::CMP::cmp(a.NAME, b.NAME); }   \
   int cmp(const KEY &key, const TYPE &b) const { return ds::CMP::cmp(key, b.NAME); }     \
   int cmp(const TYPE &a, const KEY &key) const { return ds::CMP::cmp(a.NAME, key); }     \
};

#define dsDECL_CMP_PTR(TYPE, KEY, NAME)                                                   \
struct CMP {                                                                              \
   int cmp(const TYPE &a, const TYPE &b) const { return ds::CMP::cmp(a->NAME, b->NAME); } \
   int cmp(const KEY &key, const TYPE &b) const { return ds::CMP::cmp(key, b->NAME); }    \
   int cmp(const TYPE &a, const KEY &key) const { return ds::CMP::cmp(a->NAME, key); }    \
};

#define dsDECL_CMP_NAMED(CMPNAME, TYPE, KEY, NAME)                                        \
struct CMPNAME {                                                                          \
   int cmp(const TYPE &a, const TYPE &b) const { return ds::CMP::cmp(a.NAME, b.NAME); }   \
   int cmp(const KEY &key, const TYPE &b) const { return ds::CMP::cmp(key, b.NAME); }     \
   int cmp(const TYPE &a, const KEY &key) const { return ds::CMP::cmp(a.NAME, key); }     \
};

#define dsDECL_CMP_PTR_NAMED(CMPNAME, TYPE, KEY, NAME)                                    \
struct CMPNAME {                                                                          \
   int cmp(const TYPE &a, const TYPE &b) const { return ds::CMP::cmp(a->NAME, b->NAME); } \
   int cmp(const KEY &key, const TYPE &b) const { return ds::CMP::cmp(key, b->NAME); }    \
   int cmp(const TYPE &a, const KEY &key) const { return ds::CMP::cmp(a->NAME, key); }    \
};


template<class T>
class DEFAULT_CTOR {
public:
   DEFAULT_CTOR (void) : val() {}
   DEFAULT_CTOR (const T& v) : val(v) {}

   T& operator=        (const T &v)    { val = v; return *this; }
   operator const T&   (void) const    { return val; }
   operator T&         (void)          { return val; }

   const T&   Get (void) const    { return val; }
   T&         Get (void)          { return val; }
private:
   T val;
};
//
// Swap functor
//
template <class T> 
class dsSWAP {
public:
   void operator ()     (T &a, T &b) const { T t = a; a = b; b = t; }
   void copy(T & dst, const T & src) const { dst = src; }
   typedef T TMP_T;
};

// swap function
template <typename T> void dsSwap(T& a, T& b) { T t = a; a = b; b = t; }

//
// ???
//
template <class KEY, class VAL> class dsPAIR {
public:
   KEY      key;
   VAL      val;

   dsPAIR      (void)                                          {}
   dsPAIR      (const KEY &k, const VAL &v) : key(k), val(v)   {}

   bool operator == (const dsPAIR<KEY, VAL> &compared) const
   {
      return key == compared.key && val == compared.val;
   }

   bool operator != (const dsPAIR<KEY, VAL> &compared) const
   {
      return !(*this==compared);
   }
};

template <class KEY, class VAL>
__INLINE BOOL operator < (const dsPAIR<KEY, VAL> &a, const dsPAIR<KEY, VAL> &b) { return a.key < b.key; }

template <class KEY, class VAL>
__INLINE BOOL operator < (const dsPAIR<KEY, VAL> &a, const KEY &b) { return a.key < b; }

template <class KEY, class VAL>
__INLINE BOOL operator < (const KEY &a, const dsPAIR<KEY, VAL> &b) { return a < b.key; }

template <class KEY, class VAL>
__INLINE dsPAIR<KEY, VAL> dsMakePair   (const KEY &key, const VAL &val) { return dsPAIR<KEY, VAL>(key, val); }

////////////////////////////////////////////////////////////////////////////////////////////

//
// Malloc allocator
//
template <class T> class dsMALLOC_ALLOCATOR {
public:
   T*   Alloc  (void) { return apNEW T(); }
   void Delete (T *t) { delete t; }
};

class dsNULL_TYPE {};

//
// class dsSELECT
// Selects one of two types based upon a boolean constant
// Result evaluates to T if flag is true, and to U otherwise.
//
template <bool flag, typename T, typename U>
struct dsSELECT {
   typedef T Result;
};
template <typename T, typename U>
struct dsSELECT <false, T, U> {
   typedef U Result;
};

template <typename T>
class dsTRAIT {
   template <class U> struct _POINTER_TRAITS {
      enum { result = false };
      typedef dsNULL_TYPE POINTER_TYPE;
   };
   template <class U> struct _POINTER_TRAITS<U*> {
      enum { result = true };
      typedef U POINTER_TYPE;
   };

   template <class U> struct _REFERENCE_TRAITS {
      enum { result = false };
      typedef U REFERENCE_TYPE;
   };
   template <class U> struct _REFERENCE_TRAITS<U&> {
      enum { result = true };
      typedef U REFERENCE_TYPE;
   };

   template <class U> struct _POINTER_TO_MEMBER_TRAITS {
      enum { result = false };
   };
   template <class U, class V> struct _POINTER_TO_MEMBER_TRAITS<U V::*> {
      enum { result = true };
   };

   template <class U> struct _CONST_TRAITS {
      typedef U Result;
      enum { isConst = 0 };
   };
   template <class U> struct _CONST_TRAITS<const U> {
      typedef U Result;
      enum { isConst = 1 };
   };

   template <typename U> struct _GET_PTR {
      U* operator ()     (U& u) { return &u; }
   };
   template <typename U> struct _GET_PTR<U*> {
      U* operator ()     (U* u) { return  u; }
   };

   template <typename U> struct _GET_REF {
      U&  operator ()     (U& u) { return u; }
   };
   template <typename U> struct _GET_REF<U*> {
      U&  operator ()     (U* u) { return *u; }
   };

   template<class T_A> struct _IS_ABSTRACT
   {
      // Deduction fails if T is void, function type, 
      // reference type (14.8.2/2)or an abstract class type 
      // according to review status issue #337
      //
      struct yes_type {
         char a[2];
      };
      struct no_type {
         char a[1];
      };

      template<class U_A> static no_type check_sig(U_A (*)[1]); // formal parameter is a pointer on c++ array lenght of one element
      template<class U_A> static yes_type check_sig(...);

      enum {
         result = (sizeof(yes_type) == sizeof(check_sig<T_A>(0)))
      };
   };

   //template <class T> struct _IS_VOID       { enum { result = 0 }; };
   //template <>        struct _IS_VOID<void> { enum { result = 1 }; };

public:
   enum { isPointer = _POINTER_TRAITS<T>::result };
   typedef typename _POINTER_TRAITS<T>::POINTER_TYPE POINTER_TYPE;

   enum { isReference = _REFERENCE_TRAITS<T>::result };
   typedef typename _REFERENCE_TRAITS<T>::REFERENCE_TYPE REFERENCE_TYPE;

   enum { isMemberPointer = _POINTER_TO_MEMBER_TRAITS<T>::result };

   enum { isConst = _CONST_TRAITS<T>::isConst };
   typedef typename _CONST_TRAITS<T>::Result NON_CONST_TYPE;

   enum { isAbstract = _IS_ABSTRACT<T>::result };
   //enum { isVoid     = _IS_VOID<T>::result };

   typedef typename dsSELECT<isPointer,   T, T*>::Result POINTER;
   typedef typename dsSELECT<isReference, T, T&>::Result REFERENCE;

   static POINTER   GetPtr (T &t) { return _GET_PTR<T>()(t); }
   static REFERENCE GetRef (T &t) { return _GET_REF<T>()(t); }
};

template <>
class dsTRAIT<void> {
public:
   enum { isAbstract = true };
};

//
// Compile time inheritance check
//
class _dsSIZE_1 { char dummy; };
class _dsSIZE_2 { char dummy[2]; };

template <class T, class T_BASE>
class dsIsDerivedFrom {

   static _dsSIZE_1 Test (T_BASE);
   static _dsSIZE_2 Test (...);
   static  T        MakeT();

public:
   enum {
      isDerived = (sizeof(Test(MakeT)) == sizeof(_dsSIZE_1))
   };
};

//
// Generic Make func
//
template <class T, bool isAbstract = false>
struct dsMakeFunctor {
#ifdef AP_USE_MEM_STAT
   T* operator ()(const char *file, int line) const { return apNEW_(file, line) T; }
#else
   T* operator ()(void) const { return apNEW T; }
#endif
};

template <class T>
struct dsMakeFunctor<T, true> {
#ifdef AP_USE_MEM_STAT
   T* operator ()(const char *file, int line) const { return NULL; }
#else
   T* operator ()(void) const { return NULL; }
#endif
};

#define DS_DECLARE_COPYFUNC_TYPE(typ, name) typedef void (*name) (typ *dst, typ *src)

#ifdef AP_USE_MEM_STAT

#define DS_DECLARE_MAKEFUNC_TYPE(ret, name) typedef ret* (*name) (const char *file, int line)
#define DS_CALL_MAKEFUNC(name)              name(__FILE__, __LINE__)

template <class T_BASE, class T>
T_BASE* dsMakeFunc (const char *file, int line)
{
   dsMakeFunctor<T, dsTRAIT<T>::isAbstract> maker;
   return maker(file, line);
}
#else

#define DS_DECLARE_MAKEFUNC_TYPE(ret, name) typedef ret* (*name) ()
#define DS_CALL_MAKEFUNC(name)              name()

template <class T_BASE, class T>
T_BASE* dsMakeFunc (void)
{
   dsMakeFunctor<T, dsTRAIT<T>::isAbstract> maker;
   return maker();
}
#endif



//
// Generic Copy func
//
template <class _T_PTR, class _T_SLICER>
void dsCopyFunc (_T_PTR *pDest, _T_PTR *pSrc)
{
   // *((_T_SLICER*)pDest) = *((_T_SLICER*)pSrc);
   _T_SLICER *pDestSls = polymorphic_downcast<_T_SLICER *>(pDest);
   _T_SLICER *pSrcSls  = polymorphic_downcast<_T_SLICER *>(pSrc);
   *pDestSls = *pSrcSls;

   return ;
}

//
// AI: hack - when saving classes "as a whole", T::__vtbl is saved as well
//     it should be properly restored to current __vtbl value after load
//
template <class T>
void dsRestoreVTable (T &var)
{
   T _var;     // _var has a proper __vtbl
   _var = var; // this copies the data fields from 'var' with wrong __vtbl to _var with correct __vtbl
   memcpy(&var, &_var, sizeof(T)); // this places the result back into 'var'
   return;
}

                       
#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

/*
#if defined _AP_PS3 && !defined SPU
#include <ppu_intrinsics.h>

#define fpmax(a,b) __fsel((a)-(b),a,b)
#define fpmin(a,b) __fsel((a)-(b),b,a)
#endif
*/
namespace ds {
   template <class T1, class T2>
      inline T1 min(T1 x1, T2 x2) 
   { return (x1 < x2) ? x1 : x2; }

   template <class T1, class T2>
      inline T1 max(T1 x1, T2 x2) 
   { return (x1 > x2) ? x1 : x2; }

   template <class T1, class T2, class T3>
      inline T1 min(T1 x1, T2 x2, T3 x3) 
   { return min(x1, min(x2, x3)); }

   template <class T1, class T2, class T3>
      inline T1 max(T1 x1, T2 x2, T3 x3) 
   { return max(x1, max(x2, x3)); }
}

//@E13: that's needed to avoid ambiguous call with std::min or std::max
using ds::min;
using ds::max;

template <class T>
__INLINE T range(T x, T x1, T x2) 
{
   if (x > x2) {
      return x2;
   }
   if (x < x1) {
      return x1;
   }
   return x;
}

template<class T>
void _reorder(T &val){
   BYTE *buf   = (BYTE*)&val;
   int   size  = sizeof(T);

   for (int i = 0; i < size / 2; i++) {
      BYTE tmp = buf[i];
      buf[i] = buf[size - i - 1];
      buf[size - i - 1] = tmp;
   }

   return;
}

struct dsGUID {
   DWORD d[4];
   bool operator == (const dsGUID& a) const { return d[0] == a.d[0] && d[1] == a.d[1] && d[2] == a.d[2] && d[3] == a.d[3]; }
   bool operator != (const dsGUID& a) const { return !(this->operator==(a)); }
};

template <class C>
struct dsCHECKED_CMP {
   dsCHECKED_CMP(const C & cmpSpclFrAtrx) : cmp_(cmpSpclFrAtrx) {}

   template <class T1, class T2>
      int cmp(const T1 & a, const T2 & b) const
   {
      const int cmpAB = cmp_.cmp(a, b);
      const int cmpBA = cmp_.cmp(b, a);

      STRONG_ASSERT2((cmpAB == 0 && cmpBA == 0) || (cmpAB ^ cmpBA) < 0, cmpAB, cmpBA);

      return cmpAB;
   }

   const C & cmp_;
};

#endif // _DS_COMM_H_

//
// End-of-file DS_COMM.H
//
